package com.fancy.middleware.netty.handler.v2.codec;

import com.fancy.middleware.common.annotation.V2Server;
import com.fancy.middleware.common.beans.Domain;
import com.fancy.middleware.common.beans.FrameData;
import com.fancy.middleware.common.exception.MsgException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;


/**
 * 协议解码器
 * 必须和 LengthFieldBasedFrameDecoder 一起使用，确保接到的 ByteBuf 消息是完整的
 */
@ChannelHandler.Sharable
@Service("protocolCodecSharable")
@V2Server
@Slf4j
public class V2ProtocolCodecSharable extends MessageToMessageCodec<ByteBuf, Domain> {
    /***
     * @Description: 编码
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Domain msg, List<Object> outList) throws Exception {
//        ByteBuf out = ctx.alloc().buffer();
//        // 1. 4 字节的魔数
//        out.writeBytes(new byte[]{1, 2, 3, 4});
//        // 2. 1 字节的版本,
//        out.writeByte(1);
//        // 3. 1 字节的序列化方式 jdk 0 , json 1
//        out.writeByte(0);
//        // 4. 1 字节的指令类型
//        out.writeByte(msg.getMessageType());
//        // 5. 4 个字节
//        out.writeInt(msg.getSequenceId());
//        // 无意义，对齐填充
//        out.writeByte(0xff);
//        // 6. 获取内容的字节数组
//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//        ObjectOutputStream oos = new ObjectOutputStream(bos);
//        oos.writeObject(msg);
//        byte[] bytes = bos.toByteArray();
//        // 7. 长度
//        out.writeInt(bytes.length);
//        // 8. 写入内容
//        out.writeBytes(bytes);
//        outList.add(out);
    }

    /***
     * @Description: 解码
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        try {
            log.debug("protocol decode byteBuf in \\n {}", ByteBufUtil.prettyHexDump(in));
            short dataLength = in.readShort();
            log.debug("protocol dataLength byteBuf in {}", dataLength);
            // TODO modify decode
            Domain domain = new Domain();
            int magicNum = in.readInt();
            domain.setMagicNum(magicNum);
            byte version = in.readByte();
            domain.setVersion(version);
            byte domainType = in.readByte();
            domain.setDomainType(domainType);
            FrameData frameDataEvent = new FrameData();
            short frameType = in.readShort();
            frameDataEvent.setFrameType(frameType);
            int serialNumber = in.readInt();
            frameDataEvent.setSerialNumber(serialNumber);
            int length = in.readInt();
            byte[] bytes = new byte[length];
            in.readBytes(bytes, 0, length);
            frameDataEvent.setData(bytes);
            domain.setFrameData(frameDataEvent);
            log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, domainType, frameType, serialNumber, length);
            log.debug("{}", bytes);
            out.add(domain);
        } catch (Exception e) {
            throw new MsgException(e);
        }
    }
}
